import analysis from '../libs/analysis-url';
import { clear, toString } from '../libs/css';
import download from '../libs/download';
import fetch from 'node-fetch';
import { path, compose, prop } from "ramda";
import { CollectInfo, Card, Element, Page, CollectEmitter, _CollectEmitter } from "../interfaces";
import CNF from "../config";
import { mkdirSync } from "fs";
import { camelCase } from "../libs/utils";

//把原始数据中的图片下载到本地并且修改参数中的原始地址为修改后的地址
const convertUrl = (source: any, localUrl: string, storeDir: string): Promise<string>[] => {
    const sourceUrl = 'http://res2.eqh5.com/'

    return [].concat(...source.list.map((_: any) => _.elements))
        .map(elm => {
            let src: string = elm.type == 3 ? elm.properties.imgSrc : elm.properties.src

            if (!src) return Promise.resolve('')

            src = /https?:/.test(src) ? src : sourceUrl + src
            src = elm.type == 4 && !/\?/.test(src) && !/\.svg/.test(src) ? src + '?imageMogr2/thumbnail/320' : src

            const fileName = src.split('?')[0].split('/').pop()

            elm.properties.src = elm.properties.imgSrc = `${localUrl}/${fileName}`
            return download(src, `${storeDir}/${fileName}`)
        })
}

const convertAnimate = (animation: any): string => {

    if (!animation) return ''

    const convertAnimationName = (a: any) => {
        var b, c, d = parseInt(a.type, 10);
        return 0 === d && (b = "fadeIn"), 1 === d && (c = parseInt(a.direction, 10), 0 === c && (b = "fadeInLeft"), 1 === c && (b = "fadeInDown"), 2 === c && (b = "fadeInRight"), 3 === c && (b = "fadeInUp")), 6 === d && (b = "wobble"), 5 === d && (b = "rubberBand"), 7 === d && (b = "rotateIn"), 8 === d && (b = "flip"), 9 === d && (b = "swing"), 2 === d && (c = parseInt(a.direction, 10), 0 === c && (b = "bounceInLeft"), 1 === c && (b = "bounceInDown"), 2 === c && (b = "bounceInRight"), 3 === c && (b = "bounceInUp")), 3 === d && (b = "bounceIn"), 4 === d && (b = "zoomIn"), 41 === d && (b = "zoomInRoll"), 51 === d && (b = "filterSepia"), 52 === d && (b = "filterGrayScale"), 53 === d && (b = "filterBlur"), 54 === d && (b = "filterInvert"), 55 === d && (b = "filterSaturate"), 56 === d && (b = "filterContrast"), 57 === d && (b = "filterBrightness"), 58 === d && (b = "filterHueRotate"), 59 === d && (b = "flash"), 61 === d && (b = "showWaver"), 62 === d && (b = "showBreath"), 63 === d && (b = "showWaver2"), 10 === d && (b = "fadeOut"), 11 === d && (b = "flipOutY"), 12 === d && (b = "rollIn"), 13 === d && (b = "lightSpeedIn"), 14 === d && (b = "bounceOut"), 15 === d && (b = "rollOut"), 16 === d && (b = "lightSpeedOut"), 17 === d && (c = parseInt(a.direction, 10), 0 === c && (b = "fadeOutRight"), 1 === c && (b = "fadeOutDown"), 2 === c && (b = "fadeOutLeft"), 3 === c && (b = "fadeOutUp")), 18 === d && (b = "zoomOut"), 19 === d && (c = parseInt(a.direction, 10), 0 === c && (b = "bounceOutRight"), 1 === c && (b = "bounceOutDown"), 2 === c && (b = "bounceOutLeft"), 3 === c && (b = "bounceOutUp")), 20 === d && (b = "flipInY"), 21 === d && (b = "tada"), 23 === d && (b = "hinge"), 22 === d && (b = "jello"), 66 === d && (b = "jello2"), 26 === d && (b = "twisterInDown"), 65 === d && (b = "twisterInDown2"), 27 === d && (b = "puffIn"), 28 === d && (b = "puffOut"), 29 === d && (b = "slideDown"), 67 === d && (b = "slideUp3"), 68 === d && (b = "flipInY2"), 69 === d && (b = "incline"), 70 === d && (b = "stagger"), 71 === d && (b = "shadow1"), 72 === d && (b = "shadow2"), 73 === d && (b = "flashx1"), 74 === d && (b = "flashx2"), 75 === d && (b = "change1"), 76 === d && (b = "entrance"), 77 === d && (b = "flipInx"), 78 === d && (b = "flipInxy"), 79 === d && (b = "diffusion"), 80 === d && (b = "bachelordom01"), 81 === d && (b = "earthquake"), 82 === d && (b = "rotate03"), 83 === d && (b = "immigration"), 84 === d && (b = "immigration2"), 85 === d && (b = "towards1"), 86 === d && (b = "towards2"), 87 === d && (b = "towards3"), 88 === d && (b = "shakedong"), 89 === d && (b = "Shrinko"), 90 === d && (b = "immigration3"), 91 === d && (b = "immigration4"), 92 === d && (b = "flicker"), 93 === d && (b = "searchlight"), 94 === d && (b = "rotatea3"), 95 === d && (b = "swing2"), 96 === d && (b = "vague"), 97 === d && (b = "entrance2"), 98 === d && (b = "changea2"), 99 === d && (b = "changea3"), 100 === d && (b = "changea4"), 101 === d && (b = "movement"), 102 === d && (b = "swingshuo"), 103 === d && (b = "filter142"), 104 === d && (b = "filter143"), 30 === d && (b = "slideUp"), 64 === d && (b = "slideUp2"), 24 === d && (b = "flipInX"), 25 === d && (b = "flipOutX"), 31 === d && (b = "twisterInUp"), 32 == d && (b = "vanishOut"), 33 == d && (b = "vanishIn"), b
    }

    const animations: {[k: string]: string[]} = {
        0: ["fadeIn"],
        1: ["fadeInLeft", "fadeInDown", "fadeInRight", "fadeInUp"],
        2: ["bounceInLeft", "bounceInDown", "bounceInRight", "bounceInUp"],
        3: ["bounceIn"],
        4: ["zoomIn"],
        5: ["rubberBand"],
        6: ["wobble"],
        7: ["rotateIn"],
        8: ["flip"],
        9: ["swing"],
        10: ["fadeOut"],
        11: ["flipOutY"],
        12: ["rollInRight", "rollInDown", "rollInLeft", "rollInUp"],
        13: ["lightSpeedInRight", "lightSpeedInDown", "lightSpeedInLeft", "lightSpeedInUp"],
        14: ["bounceOut"],
        15: ["rollOutRight", "rollOutDown", "rollOutLeft", "rollOutUp"],
        16: ["lightSpeedOutRight", "lightSpeedOutDown", "lightSpeedOutLeft", "lightSpeedOutUp"],
        17: ["fadeOutRight", "fadeOutDown", "fadeOutLeft", "fadeOutUp"],
        18: ["zoomOut"],
        19: ["bounceOutRight", "bounceOutDown", "bounceOutLeft", "bounceOutUp"],
        20: ["flipInY"],
        21: ["tada"],
        22: ["jello"],
        23: ["flash"],
        24: ["flipInX"],
        25: ["flipOutX"],
        26: ["twisterInDownRight", "twisterInDownDown", "twisterInDownLeft", "twisterInDownUp"],
        27: ["puffIn"],
        28: ["puffOut"],
        29: ["slideDown"],
        30: ["slideUp"],
        31: ["twisterInUpRight", "twisterInUpDown", "twisterInUpLeft", "twisterInUpUp"],
        32: ["hingeRight", "hingeLeft"],
        particles: ["particles"],
        typer: ["typer"]
    }
    return animation.type === -1 ? '' : `${animations[animation.type][animation.direction] || animations[animation.type][0]} ${animation.duration}s ${animation.linear ? 'linear' : 'ease'} ${animation.delay}s ${animation.count ? 'infinite' : 1}`
}

function convertStyle(css: { [k: string]: string | number }) {
    if (!css.backgroundColor) Reflect.deleteProperty(css, 'backgroundColor')

    if (css.opacity == 1) Reflect.deleteProperty(css, 'opacity')
    if (css.transform === 'rotateZ(0deg)') Reflect.deleteProperty(css, 'transform')
    if (css.textAlign === 'left') Reflect.deleteProperty(css, 'textAlign')

    if (css.paddingBottom == 0) Reflect.deleteProperty(css, 'paddingBottom')
    if (css.paddingTop == 0) Reflect.deleteProperty(css, 'paddingTop')

    if (css.borderWidth == 0) {
        Reflect.deleteProperty(css, 'borderWidth')
        Reflect.deleteProperty(css, 'borderStyle')
        Reflect.deleteProperty(css, 'borderColor')
    }

    if (!css.borderRadius || !parseInt(css.borderRadius.toString())) Reflect.deleteProperty(css, 'borderRadius')
    if (!css.borderRadiusPerc || !parseInt(css.borderRadiusPerc.toString())) Reflect.deleteProperty(css, 'borderRadiusPerc')
    if (!css.borderBottomRightRadius || !parseInt(css.borderBottomRightRadius.toString())) Reflect.deleteProperty(css, 'borderBottomRightRadius')
    if (!css.borderBottomLeftRadius || !parseInt(css.borderBottomLeftRadius.toString())) Reflect.deleteProperty(css, 'borderBottomLeftRadius')
    if (!css.borderTopRightRadius || !parseInt(css.borderTopRightRadius.toString())) Reflect.deleteProperty(css, 'borderTopRightRadius')
    if (!css.borderTopLeftRadius || !parseInt(css.borderTopLeftRadius.toString())) Reflect.deleteProperty(css, 'borderTopLeftRadius')

    if (css.boxShadow === '0px 0px 0px rgba(0,0,0,0.5)') {
        Reflect.deleteProperty(css, 'boxShadow')
        Reflect.deleteProperty(css, 'boxShadowDirection')
        Reflect.deleteProperty(css, 'boxShadowSize')
    }

    Reflect.deleteProperty(css, 'content')

    let newCss: { [k: string]: string | number } = {}
    for (let key in css) {
        newCss[camelCase(key)] = css[key]
    }
    return newCss
}

function addPx(css: { [k: string]: string }) {
    let needle = ['width', 'height', 'top', 'left', 'marginLeft', 'marginTop', 'borderWidth', 'fontSize', 'borderRadius', 'borderRadiusPerc', 'borderBottomRightRadius', 'borderBottomLeftRadius', 'borderTopRightRadius', 'borderTopLeftRadius', 'boxShadowDirection', 'boxShadowSize']

    for (let key in css) {
        if (needle.includes(key) && !/px/.test(css[key])) css[key] = css[key] + 'px'
    }

    return css
}

const convertCss = compose(addPx, convertStyle)

function convert(source: any): Page[] {
    const convertElm = (elm: any): Element => {
        let animations = path<string[]>(['properties', 'anim'], elm)
        if (!animations) animations = [];
        if (!Array.isArray(animations)) animations = [animations]
        let converted: Element = {
            content: elm.content ? elm.content : ''
            , css: clear(convertCss(elm.css))
            , classes: []
            , animations: animations.map(convertAnimate)
        }

        switch (elm.type.toString()) {
            //图片类型
            case '3':
            case '4':
                if (elm.type == '3') {
                    //背景图片或颜色
                    if (elm.properties.imgSrc) {
                        converted.content = `<img src="${elm.properties.imgSrc}" class="card-bg" />`
                    } else {
                        converted.css.backgroundColor = elm.properties.bgColor
                    }
                    converted.classes.push('card-bg')
                } else {
                    //一般图片
                    converted.content = `<img src="${elm.properties.src}" style="${toString(clear(addPx(elm.properties.imgStyle)))}" />`
                }

                if ((elm.properties.clc && elm.properties.clc === 'edit_move') || elm.isEditable) {
                    converted.classes.push('editable')
                }
                break
            case 'h': //SVG
                let fill = prop('fill', path(['items', '0'], elm.properties))
                converted.content = `<xtb-svg data-src="${elm.properties.src}" data-fill="${fill}"/>`
                break
            case '2': //文字类型
                converted.content = converted.content.replace(/易企秀/g, '喜帖吧')
                converted.classes.push('text', 'editable')
                break
        }
        return converted
    }

    return source.list.map((p: any) => ({
        elements: p.elements.map(convertElm)
    })
    )
}

function collect(url: string) {
    const emitter: _CollectEmitter = new CollectEmitter()
    const emit = (ev: string | symbol) => (...args: any[]) => emitter.emit(ev, ...args)

    analysis(url)
        .then(info => {
            emitter.emit('analysised', info)

            return fetch(info.url)
                .then(_ => _.json())
                .then((source: any) => {
                    let downloadDir = `${CNF.LOCAL_IMG_STORE || './'}/${info.id}`
                    try { mkdirSync(downloadDir) } catch (e) { }
                    let downloadTasks = convertUrl(source, `/collect/${info.id}`, downloadDir)

                    emitter.emit('fetched', { title: info.title, pages: convert(source), origin: url })
                    emitter.emit('downloading', downloadTasks)

                    return Promise.all(downloadTasks).then(emit('downloaded'))
                })
        })
        .catch(emit('error'))

    return emitter
}

export default collect